﻿using Edu.Common.Logs;
using Edu.Common.Win32;
using Edu.Common.Win32.Enums;
using Edu.Presentation;
using Gma.System.MouseKeyHook;
using MainApp.Utils;
using MainApp.Utils.WindowsDesktops;
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Threading;

namespace MainApp
{
    partial class MainWindow
    {
        private DispatcherTimer _timer;
        private bool _timerIsDoing = false;
        private VirtualDesktopManager _vdm = null;

        private void StartTimer()
        {
            try { _vdm = new VirtualDesktopManager(); } catch { }
            _timer = new DispatcherTimer
            {
                Interval = TimeSpan.FromSeconds(1)
            };
            _timer.Tick += Timer_Tick;
            _timer.Start();
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            if (_timerIsDoing) return;
            try
            {
                _timerIsDoing = true;
                //始终保持显示在当前的虚拟桌面中
                TryKeepDesktop();
                //尝试置顶演示窗口
                TryForegroundSlideViewWindow();
                //尝试关闭其他的ppt文件
                TryCloseOtherPptFiles();
            }
            catch { }
            finally
            {
                _timerIsDoing = false;
            }
        }

        /// <summary>
        /// 始终保持显示在当前的虚拟桌面中
        /// </summary>
        private void TryKeepDesktop()
        {
            var vdm = _vdm;
            if (vdm == null)
                return;
            var pptFile = AppConfig.Current.RunFilePath;
            //var slideHwnd = PPTTools.GetSlideViewWindowHandle(pptFile);
            //var slideHwnd = PPTTools.GetDocumentHwnd(pptFile);
            IntPtr slideHwnd = IntPtr.Zero;
            try
            {
                var currentWindowInDesktop = Hwnd == IntPtr.Zero ? true : vdm.IsWindowOnCurrentVirtualDesktop(Hwnd);
                var slideWindowInDesktop = slideHwnd == IntPtr.Zero ? true : vdm.IsWindowOnCurrentVirtualDesktop(slideHwnd);
                if (slideWindowInDesktop && currentWindowInDesktop)
                    return;
                using (var form = new System.Windows.Forms.Form()
                {
                    Width = 1,
                    Height = 1,
                    Left = -100,
                    Top = -100,
                    ShowInTaskbar = false,
                    FormBorderStyle = System.Windows.Forms.FormBorderStyle.None,
                })
                {
                    form.Show(null);
                    var desktopId = vdm.GetWindowDesktopId(form.Handle);
                    if (desktopId == Guid.Empty) return;
                    if (!slideWindowInDesktop)
                        try { vdm.MoveWindowToDesktop(slideHwnd, desktopId); } catch { }
                    if (!currentWindowInDesktop)
                        try { vdm.MoveWindowToDesktop(Hwnd, desktopId); } catch { }
                }
            }
            catch { }
        }

        /// <summary>
        /// 尝试置顶演示窗口
        /// </summary>
        private void TryForegroundSlideViewWindow()
        {
            var foregroundSlideViewWindow = AppConfig.Current.ForegroundSlideViewWindow;
            if (!foregroundSlideViewWindow)
                return;
            var settingsWindow = Tools.FindWindow<SettingsWindow>();
            if (settingsWindow != null) return;
            var pptFile = AppConfig.Current.RunFilePath;
            PPTTools.TryForegroundSlideViewWindow(pptFile);
        }

        /// <summary>
        /// 尝试关闭其他的ppt文件
        /// </summary>
        private void TryCloseOtherPptFiles()
        {
            var closeOtherPptFile = AppConfig.Current.CloseOtherPptFile;
            if (!closeOtherPptFile)
                return;
            var pptFile = AppConfig.Current.RunFilePath;
            PPTTools.TryCloseOtherFiles(pptFile);
        }
    }

    /// <summary>
    /// 保持窗口置顶工具
    /// </summary>
    class KeepTopMostTool : System.Windows.Forms.NativeWindow, IDisposable
    {
        #region 字段定义
        private IntPtr _hWnd;
        private bool _keepTopmost = false;
        private Thread _keepTopmostThread;
        private int _keepTopmostTimespan = int.MaxValue;
        private string[] _excludeClassNames;

#if DEBUG
        private bool _subscribeGlobalMouse = false;
#else
        private bool _subscribeGlobalMouse = true;
#endif
        private IKeyboardMouseEvents _keyboardMouseEvents;
        private DateTime _lastKeyboardMouseActiveDate;

        private int _disposeFlag = 0;
        #endregion

        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="hWnd">要置顶的窗口句柄</param>
        /// <param name="keepTopmostTimespan">单位：毫秒</param>
        /// <param name="excludeClassNames">要排除的窗口类名集合</param>
        public KeepTopMostTool(IntPtr hWnd, int keepTopmostTimespan, params string[] excludeClassNames)
        {
            if (hWnd == IntPtr.Zero) throw new ArgumentException($"{nameof(hWnd)}参数无效");
            _hWnd = hWnd;
            _excludeClassNames = excludeClassNames;
            _keepTopmostTimespan = keepTopmostTimespan;
            _lastKeyboardMouseActiveDate = DateTime.Now;
        }
        ~KeepTopMostTool()
        {
            Dispose(false);
        }
        #endregion

        #region 公共方法
        /// <summary>
        /// 停止窗口指定保持
        /// </summary>
        public void StopKeepTopmost()
        {
            _keepTopmost = false;
            var thread = _keepTopmostThread;
            _keepTopmostThread = null;
            //取消全局鼠标监听
            UnSubscribeGlobalMouseEvent();
            //重置保持置顶线程
            if (thread?.IsAlive ?? false)
            {
                try { thread?.Abort(); } catch { }
            }
            //释放句柄
            try { ReleaseHandle(); } catch { }
        }
        /// <summary>
        /// 启动窗口指定保持
        /// </summary>
        public void StartKeepTopmost()
        {
            var hWnd = _hWnd;
            if (hWnd == IntPtr.Zero) return;
            StopKeepTopmost();
            _keepTopmost = true;
            //启动全局鼠标监听
            if (_subscribeGlobalMouse)
                SubscribeGlobalMouseEvent();
            //启动保持置顶线程
            var thread = new Thread(ThreadWorkProc) { IsBackground = true };
            thread.Start();
            _keepTopmostThread = thread;
            //分配句柄
            try { AssignHandle(hWnd); } catch { }
        }
        /// <summary>
        /// 资源释放
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
        }
        #endregion

        #region 私有方法
        private void Dispose(bool disposing)
        {
            if (Interlocked.CompareExchange(ref _disposeFlag, 1, 0) != 0) return;
            if (disposing) GC.SuppressFinalize(this);
            StopKeepTopmost();
        }
        /// <summary>
        /// WndProc
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            base.WndProc(ref m);
            try
            {
                if (m.Msg == (int)WinMsg.WM_ACTIVATEAPP)
                {
                    if (m.WParam.ToInt32() != 1 && _keepTopmost)
                    {
                        //int threadId = m.LParam.ToInt32();
                        //切换窗口到置顶显示状态
                        SwitchWindowTopmost();
                    }
                    return;
                }
            }
            catch { }
        }
        /// <summary>
        /// 保持置顶线程
        /// </summary>
        private void ThreadWorkProc()
        {
            try
            {
                var interval = _keepTopmostTimespan;
                while (_keepTopmost)
                {
                    //切换窗口到置顶显示状态
                    if (_keepTopmost)
                        SwitchWindowTopmost();
                    try { TryForegroundSlideViewWindow(); } catch { }
                    try { TryCloseOtherPptFiles(); } catch { }
                    try { TryCheckGotoFirstPage(); } catch { }
                    Thread.Sleep(interval);
                }
            }
            catch { }
        }
        /// <summary>
        /// 切换窗口到置顶显示状态
        /// </summary>
        private void SwitchWindowTopmost()
        {
            try { ClrMethods.HwndToTopmost(_hWnd, _excludeClassNames); }
            catch { }
        }
        /// <summary>
        /// 尝试置顶演示窗口
        /// </summary>
        private void TryForegroundSlideViewWindow()
        {
            var foregroundSlideViewWindow = AppConfig.Current.ForegroundSlideViewWindow;
            if (!foregroundSlideViewWindow)
                return;
            var settingsWindow = PresentationHelper.ExecuteOnUI(() => Tools.FindWindow<SettingsWindow>());
            if (settingsWindow != null) return;
            var pptFile = AppConfig.Current.RunFilePath;
            PPTTools.TryForegroundSlideViewWindow(pptFile);
        }

        /// <summary>
        /// 尝试关闭其他的ppt文件
        /// </summary>
        private void TryCloseOtherPptFiles()
        {
            var closeOtherPptFile = AppConfig.Current.CloseOtherPptFile;
            if (!closeOtherPptFile)
                return;
            var pptFile = AppConfig.Current.RunFilePath;
            PPTTools.TryCloseOtherFiles(pptFile);
        }
        /// <summary>
        /// 订阅全局键盘鼠标事件监听
        /// </summary>
        private void SubscribeGlobalMouseEvent()
        {
            try
            {
                _lastKeyboardMouseActiveDate = DateTime.Now;
                var keyboardMouseEvents = _keyboardMouseEvents;
                if (keyboardMouseEvents != null)
                {
                    keyboardMouseEvents.Dispose();
                    _keyboardMouseEvents = null;
                }
                keyboardMouseEvents = Hook.GlobalEvents();
                _keyboardMouseEvents = keyboardMouseEvents;
                keyboardMouseEvents.MouseMove += KeyboardMouseEvents_MouseMove;
                keyboardMouseEvents.MouseDown += KeyboardMouseEvents_MouseDown;
                keyboardMouseEvents.KeyDown += KeyboardMouseEvents_KeyDown;
            }
            catch (Exception ex)
            {
                var logger = LogManager.GetLogger<MainWindow>();
                logger?.Error("启动鼠标键盘监听失败", ex);
            }
        }

        /// <summary>
        /// 取消订阅全局键盘鼠标事件监听
        /// </summary>
        private void UnSubscribeGlobalMouseEvent()
        {
            var keyboardMouseEvents = _keyboardMouseEvents;
            if (keyboardMouseEvents == null) return;
            using (keyboardMouseEvents)
            {
                keyboardMouseEvents.MouseMove -= KeyboardMouseEvents_MouseMove;
                keyboardMouseEvents.MouseDown -= KeyboardMouseEvents_MouseDown;
                keyboardMouseEvents.KeyDown += KeyboardMouseEvents_KeyDown;
            }
        }

        private void TryCheckGotoFirstPage()
        {
            var dateNow = DateTime.Now;
            var maxFreeTimes = AppConfig.Current.MaxFreeTimes;
            if (maxFreeTimes <= 0) return;
            if (dateNow > _lastKeyboardMouseActiveDate)
            {
                var timespan = dateNow.Subtract(_lastKeyboardMouseActiveDate);
                if (timespan.TotalMinutes <= maxFreeTimes)
                {
#if DEBUG
                    if (Debugger.IsAttached)
                    {
                        Debug.WriteLine($"free times:{timespan.TotalMinutes} min，max:{maxFreeTimes} min");
                    }
#endif
                    return;
                }
                //返回第一页
                PPTTools.TryGotoFirstPage();
                _lastKeyboardMouseActiveDate = dateNow;
            }
        }

        private void OnKeyboardMouseActive(EventArgs e)
        {
            _lastKeyboardMouseActiveDate = DateTime.Now;
#if DEBUG
            if (Debugger.IsAttached)
            {
                if (e is System.Windows.Forms.MouseEventArgs mouseEventArgs)
                {
                    Debug.WriteLine($"mouse->{mouseEventArgs.X},{mouseEventArgs.Y}");
                    return;
                }
                if (e is System.Windows.Forms.KeyEventArgs keyEventArgs)
                {
                    Debug.WriteLine($"keyboard->{keyEventArgs.KeyCode}");
                    return;
                }
            }
#endif
        }

        private void KeyboardMouseEvents_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            OnKeyboardMouseActive(e);
        }

        private void KeyboardMouseEvents_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            OnKeyboardMouseActive(e);
        }

        private void KeyboardMouseEvents_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            OnKeyboardMouseActive(e);
        }
        #endregion
    }
}
